use pest::{iterators::Pairs, Parser};
use pest_derive::Parser;
use std::fmt;

#[derive(Parser)]
#[grammar = "parser.pest"]
pub struct SysYParser;


pub fn parse_file(input: &str) {
    let mut formatter = Formatter::new();
    match SysYParser::parse(Rule::program, &input) {
        Ok(pairs) => {
            visit_pairs(pairs, &mut formatter);
        }
        Err(error) => {
            report_errors(error);
        }
    }
    println!("{}", formatter.finish());
}

// comp_unit = { (func_def | decl)* }
fn visit_pairs(pairs: pest::iterators::Pairs<Rule>, mut formatter: &mut Formatter){
    pairs.for_each(|pair|{
        match pair.as_rule() {
            Rule::EOI => (),
            Rule::comp_unit => visit_pairs(pair.into_inner(), &mut formatter),

            Rule::IDENT
            | Rule::INTEGER_CONST => formatter.write(pair.as_str()),

            Rule::COMMENT => (),

            Rule::PLUS
            | Rule::MINUS
            | Rule::MUL
            | Rule::DIV
            | Rule::MOD
            | Rule::ASSIGN
            | Rule::EQ
            | Rule::NEQ
            | Rule::LT
            | Rule::GT
            | Rule::LE
            | Rule::GE
            | Rule::NOT
            | Rule::AND
            | Rule::OR => {
                formatter.space();
                formatter.write(pair.as_str());
                formatter.space();
            },

            Rule::L_PAREN
            | Rule::R_PAREN
            | Rule::L_BRACKT
            | Rule::R_BRACKT => formatter.write(pair.as_str()),
            
            Rule::SEMICOLON => {formatter.write(";"); formatter.newline();}

            Rule::COMMA => formatter.write(", "),

            Rule::L_BRACE => {
                formatter.space();
                formatter.write("{");
                formatter.newline();
            },
            Rule::R_BRACE => {
                formatter.newline();
                formatter.write("}");
                formatter.newline();
            }

            Rule::CONST
            | Rule::INT
            | Rule::VOID
            | Rule::IF
            | Rule::WHILE
            | Rule::RETURN => {
                formatter.write(pair.as_str());
                formatter.space();
            },

            Rule::ELSE => {
                formatter.write(pair.as_str());
                formatter.enter_else();
                formatter.newline();
            },

            Rule::BREAK
            | Rule::CONTINUE => formatter.write(pair.as_str()),

            Rule::decl
            | Rule::const_decl
            | Rule::b_type
            | Rule::const_def
            | Rule::const_init_val

            | Rule::var_decl

            | Rule::func_type
            | Rule::func_f_params
            | Rule::func_f_param
            | Rule::block => visit_pairs(pair.into_inner(), &mut formatter),

            Rule::block_item => {
                formatter.indent();
                visit_pairs(pair.into_inner(), &mut formatter);
                formatter.unindent();
            }

            Rule::func_def => {
                formatter.write("\n");
                visit_pairs(pair.into_inner(), &mut formatter);
            }


            Rule::init_val => {
                formatter.enter_init_val();
                visit_pairs(pair.into_inner(), &mut formatter);
                // formatter.leave_init_val();
            }

            Rule::var_def => {
                formatter.enter_init_val();
                visit_pairs(pair.into_inner(), &mut formatter);
                formatter.leave_init_val();
            }


            Rule::stmt
            | Rule::stmt_assign
            | Rule::stmt_exp

            | Rule::stmt_break
            | Rule::stmt_continue
            | Rule::stmt_return =>{
                // formatter.newline();
                visit_pairs(pair.into_inner(), &mut formatter)
            }

            Rule::stmt_if => {
                formatter.unnewline();
                visit_pairs(pair.into_inner(), &mut formatter);

            }

            Rule::stmt_while => {
                visit_pairs(pair.into_inner(), &mut formatter);
                formatter.newline();
            }

            Rule::stmt_else => {
                visit_pairs(pair.into_inner(), &mut formatter);
                formatter.leave_else();
            }

            Rule::exp
            | Rule::cond
            | Rule::l_val
            | Rule::primary_exp
            | Rule::number
            | Rule::unary_exp
            | Rule::unary_op
            | Rule::func_r_params
            | Rule::mul_exp
            | Rule::add_exp
            | Rule::rel_exp
            | Rule::eq_exp
            | Rule::l_and_exp
            | Rule::l_or_exp
            | Rule::const_exp => visit_pairs(pair.into_inner(), &mut formatter),

            _ => unimplemented!()
        }
    });
}


fn report_errors<T: std::fmt::Debug>(error: T){
    println!("{:?}", error);
}

const INDENT_SIZE: usize = 4;

// 代码格式化器：管理缩进、换行、输出
#[derive(Debug)]
struct Formatter {
    output: String,
    indent_level: usize,    // 当前缩进级别
    need_newline: bool,     // 是否需要先换行再写内容
    in_init_val: bool,
    need_space: bool,
    in_else: bool,
}

impl Formatter {
    // 初始化格式化器（默认4空格缩进）
    fn new() -> Self {
        Formatter {
            output: String::new(),
            indent_level: 0,
            need_newline: false,
            in_init_val: false,
            need_space: false,
            in_else: false,
        }
    }
    
    fn enter_init_val(&mut self) {
        self.in_init_val = true;
    }

    fn leave_init_val(&mut self) {
        self.in_init_val = false
    }

    fn enter_else(&mut self) {
        self.in_else = true;
    }

    fn leave_else(&mut self) {
        self.in_else = false;
    }

    // 增加缩进
    fn indent(&mut self) {
        self.indent_level += 1;
    }

    // 减少缩进
    fn unindent(&mut self) {
        if self.indent_level > 0 {
            self.indent_level -= 1;
        }
    }

    // 写入缩进（仅在需要换行时）
    fn write_indent(&mut self){
        for _ in 0..self.indent_level * INDENT_SIZE {
            self.output.push(' ');
        }
    }

    // 写入字符串：自动处理换行和缩进
    fn write(&mut self, s: &str){
        if self.need_space{
            if !self.need_newline {};
            self.output.push_str(" ");
            self.need_space = false;
        }
        // 不需要换行：直接写
        if !self.need_newline { //|| self.in_init_val {
            self.output.push_str(s);
            return;
        }

        // 需要换行：先写换行+缩进，再写内容
        self.output.push('\n');
        self.write_indent();
        self.output.push_str(s);
        self.need_newline = false; // 重置换行标记
    }

    // 标记需要换行（下一次write前先换行）
    fn newline(&mut self) {
        if self.in_init_val {
            self.need_newline = false;
        }else {
            self.need_newline = true;
        }
    }

    fn unnewline(&mut self) {
        if self.in_else {
            self.need_newline = false;
        }
        
    }

    // 写入空格（仅在非注释时）
    fn space(&mut self){
        self.need_space = true;
    }

    // 获取最终格式化结果
    fn finish(self) -> String {
        self.output.trim_start_matches('\n') // 移除开头空行
            .to_string()
    }
}
